/*
 * Copyright (c) 2005, 2014 vacoor
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 */
package org.vacoor.nothing.common.reflect;

import org.vacoor.nothing.common.util.StringUtils;
import org.vacoor.nothing.common.util.Throwables;

import java.beans.Expression;
import java.util.Map;

/**
 * TODO 添加路径处理
 * <p/>
 * 对 Array/List Map/Bean 反射读取和修改提供一个相对统一的方式
 * <p/>
 * 使用 {@link java.beans.Expression} 来简化反射的方法调用
 * 只能调用 public 方法
 *
 * @author vacoor
 */
public class Mates<T> {
    private static final String GET = "get";
    private static final String SET = "set";
    private static final String PUT = "put";
    private final T target;

    public static <T> Mates<T> from(T target) {
        return new Mates<T>(target);
    }

    private Mates(T target) {
        this.target = target;
    }

    public Mates set(String property, Object value) {
        if (target instanceof Map<?, ?>) {
            invoke(PUT, property, value);
        } else {
            invoke(SET + StringUtils.capitalize(property), value);
        }
        return this;
    }


    public Mates set(int index, Object value) {
        invoke(SET, new Object[]{index, value});
        return this;
    }


    @SuppressWarnings("unchecked")
    public <V> V get(String property) {
        return (V) (target instanceof Map<?, ?> ? invoke(GET, property) : invoke(GET + StringUtils.capitalize(property)));
    }

    @SuppressWarnings("unchecked")
    public <V> V get(int index) {
        return (V) invoke(GET, index);
    }

    @SuppressWarnings("unchecked")
    public <V> V invoke(String method, Object... args) {
        return (V) execute(target, method, args);
    }

    Object execute(Object target, String method, Object... args) {
        try {
            Expression expr = new Expression(target, method, args);
            expr.execute();
            return expr.getValue();
        } catch (Exception e) {
            throw Throwables.unchecked(e);
        }
    }

    private T getTarget() {
        return target;
    }
}
